package com.ophiux.common.core.aspect;

import cn.hutool.json.JSONUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Aspect
@Component
@Slf4j
public class RequestMappingAspect {
    /**
     * 排除日志打印接口
     */
    private List<String> filterMethodList = Arrays.asList("saveLog");

    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void getMapping() {
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void postMapping() {
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.PutMapping)")
    public void putMapping() {
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.DeleteMapping)")
    public void deleteMapping() {
    }

//	@Pointcut("execution(* com.esiran.greenadmin.admin.controller..*.*(..))")
//    public void restController() {
//	}

    @SneakyThrows
    @Around("deleteMapping() || postMapping() || putMapping()")
    public Object doBefore(ProceedingJoinPoint joinPoint) {
        Object result = "";
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        long startTime = System.currentTimeMillis();
        log.info("\n方法" + className + "." + methodName + "()--->==========开始=====================");
        if (filterMethodList.contains(methodName)) {
            return joinPoint.proceed();
        }
        try {
            Object[] methodArgs = joinPoint.getArgs();
            Object[] arguments = new Object[methodArgs.length];

            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                log.info("请求方法 {}.{}", className, methodName);
                log.info("未获取到request请求,直接结束");
                return joinPoint.proceed();
            }
            HttpServletRequest request = attributes.getRequest();

            /**
             * 获取方法的参数值数组
             */
            log.info("请求连接 {},请求类型 {},请求ip={},请求方法 {}.{}", request.getRequestURL().toString(), request.getMethod(), getIpAddress(request), className, methodName);
//            log.info("请求token={}",request.getHeader("Authorization"));

            for (int i = 0; i < methodArgs.length; i++) {
                if (methodArgs[i] instanceof ServletRequest || methodArgs[i] instanceof ServletResponse || methodArgs[i] instanceof MultipartFile) {
                    //ServletRequest不能序列化，从入参里排除，否则报异常：java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
                    //ServletResponse不能序列化 从入参里排除，否则报异常：java.lang.IllegalStateException: getOutputStream() has already been called for this response
                    continue;
                }
                arguments[i] = methodArgs[i];
            }
            String paramter = "";
            if (arguments != null) {
                try {
                    paramter = JSONUtil.toJsonStr(arguments);
                } catch (Exception e) {
                    paramter = arguments.toString();
                }
            }
            log.info("请求入参 {}", paramter);
            //执行业务方法
            result = joinPoint.proceed();
        } catch (Throwable e) {
            throw e;
        } finally {
            long endTime = System.currentTimeMillis();
            log.info("\n响应参数：{}\n方法" + className + "." + methodName + "()--->========结束=======耗时：{}=======", JSONUtil.toJsonStr(result), endTime - startTime);
        }
        return result;
    }

    @Around("getMapping()")
    @SneakyThrows
    public Object doBeforeGet(ProceedingJoinPoint joinPoint) {
        Object result = "";
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        long startTime = System.currentTimeMillis();
        log.info("方法" + className + "." + methodName + "()--->==========开始=====================");
        if (filterMethodList.contains(methodName)) {
            return joinPoint.proceed();
        }
        try {
            Object[] methodArgs = joinPoint.getArgs();
            Object[] arguments = new Object[methodArgs.length];

            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                log.info("请求方法 {}.{}", className, methodName);
                log.info("未获取到request请求,直接结束");
                return joinPoint.proceed();
            }
            HttpServletRequest request = attributes.getRequest();

            /**
             * 获取方法的参数值数组
             */
            log.info("请求连接 {},请求类型 {},请求ip={},请求方法 {}.{}", request.getRequestURL().toString(), request.getMethod(), getIpAddress(request), className, methodName);
//	        log.info("请求token={}",request.getHeader("Authorization"));
            for (int i = 0; i < methodArgs.length; i++) {
                if (methodArgs[i] instanceof ServletRequest || methodArgs[i] instanceof ServletResponse || methodArgs[i] instanceof MultipartFile) {
                    //ServletRequest不能序列化，从入参里排除，否则报异常：java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
                    //ServletResponse不能序列化 从入参里排除，否则报异常：java.lang.IllegalStateException: getOutputStream() has already been called for this response
                    continue;
                }
                arguments[i] = methodArgs[i];
            }
            String paramter = "";
            if (arguments != null) {
                try {
                    paramter = JSONUtil.toJsonStr(arguments);
                } catch (Exception e) {
                    paramter = arguments.toString();
                }
            }
            log.info("请求入参 {}", paramter);
            //执行业务方法
            result = joinPoint.proceed();
        } catch (Throwable e) {
            throw e;
        } finally {
            long endTime = System.currentTimeMillis();
            log.info("\n方法" + className + "." + methodName + "()--->========结束=========耗时毫秒：{}============", endTime - startTime);
        }
        return result;
    }


    /**
     * 获取请求实际ip
     *
     * @param request
     * @return
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
